home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / utils / answer.c next >
Encoding:
C/C++ Source or Header  |  1993-02-03  |  13.2 KB  |  470 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: answer.c,v 5.5 1993/02/04 15:32:52 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.5 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: answer.c,v $
  17.  * Revision 5.5  1993/02/04  15:32:52  syd
  18.  * Add cast to silence compiler warning.
  19.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  20.  *
  21.  * Revision 5.4  1993/01/20  03:37:16  syd
  22.  * Nits and typos in the NLS messages and corresponding default messages.
  23.  * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
  24.  *
  25.  * Revision 5.3  1992/10/11  01:46:35  syd
  26.  * change dbm name to dbz to avoid conflicts with partial call
  27.  * ins from shared librarys, and from mixing code with yp code.
  28.  * From: Syd via prompt from Jess Anderson
  29.  *
  30.  * Revision 5.2  1992/10/11  01:25:58  syd
  31.  * Add undefs of tolower so BSD macro isnt used from ctype.h
  32.  * From: Syd
  33.  *
  34.  * Revision 5.1  1992/10/04  00:46:45  syd
  35.  * Initial checkin as of 2.4 Release at PL0
  36.  *
  37.  *
  38.  ******************************************************************************/
  39.  
  40. /** This program is a phone message transcription system, and
  41.     is designed for secretaries and the like, to allow them to
  42.     painlessly generate electronic mail instead of paper forms.
  43.  
  44.     Note: this program ONLY uses the local alias file, and does not
  45.       even read in the system alias file at all.
  46.  
  47. **/
  48.  
  49. #include "elmutil.h"
  50. #include "ndbz.h"
  51. #include "s_answer.h"
  52. #include "sysdefs.h"
  53. #include <ctype.h>
  54.  
  55. #ifdef BSD
  56. #undef        tolower
  57. #endif
  58.  
  59. #define  ELM        "elm"        /* where the elm program lives */
  60.  
  61. int user_data;        /* fileno of user data file   */
  62. DBZ *hash;        /* dbz file for same */
  63.  
  64. #ifdef DEBUG
  65. FILE *debugfile = stderr;
  66. int  debug = 0;
  67. #endif
  68.  
  69. char *get_alias_address(), *get_token(), *strip_parens(), *shift_lower();
  70.  
  71. static char *quit_word, *exit_word, *done_word, *bye_word;
  72.  
  73. main(argc, argv)
  74. int argc;
  75. char *argv[];
  76. {
  77.     FILE *fd;
  78.     char *address, buffer[LONG_STRING], tempfile[SLEN], *cp;
  79.     char  name[SLEN], user_name[SLEN], in_line[SLEN];
  80.     int   msgnum = 0, eof, allow_name = 0, phone_slip = 0;
  81.     int   ans_pid = getpid();
  82.     
  83. #ifdef I_LOCALE
  84.     setlocale(LC_ALL, "");
  85. #endif
  86.  
  87.     elm_msg_cat = catopen("elm2.4", 0);
  88.  
  89.     quit_word = catgets(elm_msg_cat, AnswerSet, AnswerQuitWord, "quit");
  90.     exit_word = catgets(elm_msg_cat, AnswerSet, AnswerExitWord, "exit");
  91.     done_word = catgets(elm_msg_cat, AnswerSet, AnswerDoneWord, "done");
  92.     bye_word = catgets(elm_msg_cat, AnswerSet, AnswerByeWord, "bye");
  93. /*
  94.  *    simplistic crack arguments, looking for -u/-p
  95.  *    -u = allow user names not in alias table
  96.  *    -p = prompt for phone slip messages
  97.  */
  98.     for (msgnum = 1; msgnum < argc; msgnum++) {
  99.       if (istrcmp(argv[msgnum], "-u") == 0)
  100.         allow_name = 1;
  101.       if (istrcmp(argv[msgnum], "-p") == 0)
  102.         phone_slip = 1;
  103.       if (istrcmp(argv[msgnum], "-pu") == 0) {
  104.         allow_name = 1;
  105.         phone_slip = 1;
  106.       }
  107.       if (istrcmp(argv[msgnum], "-up") == 0) {
  108.         allow_name = 1;
  109.         phone_slip = 1;
  110.       }
  111.     }
  112.  
  113.     open_alias_file();
  114.  
  115.     while (1) {
  116.       if (msgnum > 9999) msgnum = 0;
  117.     
  118.       printf("\n-------------------------------------------------------------------------------\n");
  119.  
  120. prompt:   printf(catgets(elm_msg_cat, AnswerSet, AnswerMessageTo, "\nMessage to: "));
  121.       if (fgets(user_name, SLEN, stdin) == NULL) {
  122.         putchar('\n');
  123.         exit(0);
  124.       }
  125.       if(user_name[0] == '\0')
  126.         goto prompt;
  127.       
  128.       cp = &user_name[strlen(user_name)-1];
  129.       if(*cp == '\n') *cp = '\0';
  130.       if(user_name[0] == '\0')
  131.         goto prompt;
  132.  
  133.       if ((istrcmp(user_name, quit_word) == 0) ||
  134.           (istrcmp(user_name, exit_word) == 0) ||
  135.           (istrcmp(user_name, done_word) == 0) ||
  136.           (istrcmp(user_name, bye_word)  == 0))
  137.          exit(0);
  138.  
  139.       if (translate(user_name, name) == 0)
  140.         goto prompt;
  141.  
  142.       address = get_alias_address(name, 1, 0);
  143.  
  144.       if (address == NULL || strlen(address) == 0) {
  145.         if (allow_name)
  146.           address =  name;
  147.         else {
  148.           printf(catgets(elm_msg_cat, AnswerSet, AnswerSorryNotFound,
  149.              "Sorry, could not find '%s' [%s] in list!\n"),
  150.              user_name, name);
  151.           goto prompt;
  152.         }
  153.       }
  154.  
  155.       printf("address '%s'\n", address);
  156.  
  157.       sprintf(tempfile, "%sans.%d.%d", default_temp, ans_pid, msgnum++);
  158.  
  159.       if ((fd = fopen(tempfile,"w")) == NULL)
  160.         exit(printf(catgets(elm_msg_cat, AnswerSet, AnswerCouldNotOpenWrite,
  161.             "** Fatal Error: could not open %s to write\n"),
  162.          tempfile));
  163.  
  164.  
  165.     /** Enter standard phone message fields **/
  166.       if (phone_slip) {
  167.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerCaller, "Caller: "));
  168.         printf("\n%s",buffer);
  169.         fflush(stdout);
  170.         fgets(in_line, SLEN, stdin);
  171.         if (strlen(in_line) > 1)
  172.           fprintf(fd,"%s%s",buffer,in_line);
  173.  
  174.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerOf, "of:     "));
  175.         printf("%s",buffer);
  176.         fflush(stdout);
  177.         fgets(in_line, SLEN, stdin);
  178.         if (strlen(in_line) > 1)
  179.           fprintf(fd,"%s%s",buffer,in_line);
  180.  
  181.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerPhone, "Phone:  "));
  182.         printf("%s",buffer);
  183.         fflush(stdout);
  184.         fgets(in_line, SLEN, stdin);
  185.         if (strlen(in_line) > 1)
  186.           fprintf(fd,"%s%s\n",buffer,in_line);
  187.  
  188.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerTelephoned, "TELEPHONED         - "));
  189.         printf("\n%s",buffer);
  190.         fflush(stdout);
  191.         fgets(in_line, SLEN, stdin);
  192.         if (strlen(in_line) > 1)
  193.           fprintf(fd,"%s%s",buffer,in_line);
  194.  
  195.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerCalledToSeeYou, "CALLED TO SEE YOU  - "));
  196.         printf("%s",buffer);
  197.         fflush(stdout);
  198.         fgets(in_line, SLEN, stdin);
  199.         if (strlen(in_line) > 1)
  200.           fprintf(fd,"%s%s",buffer,in_line);
  201.  
  202.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerWantsToSeeYou, "WANTS TO SEE YOU   - "));
  203.         printf("%s",buffer);
  204.         fflush(stdout);
  205.         fgets(in_line, SLEN, stdin);
  206.         if (strlen(in_line) > 1)
  207.           fprintf(fd,"%s%s",buffer,in_line);
  208.  
  209.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerReturnedYourCall, "RETURNED YOUR CALL - "));
  210.         printf("%s",buffer);
  211.         fflush(stdout);
  212.         fgets(in_line, SLEN, stdin);
  213.         if (strlen(in_line) > 1)
  214.           fprintf(fd,"%s%s",buffer,in_line);
  215.  
  216.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerPleaseCall, "PLEASE CALL        - "));
  217.         printf("%s",buffer);
  218.         fflush(stdout);
  219.         fgets(in_line, SLEN, stdin);
  220.         if (strlen(in_line) > 1)
  221.           fprintf(fd,"%s%s",buffer,in_line);
  222.  
  223.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerWillCallAgain, "WILL CALL AGAIN    - "));
  224.         printf("%s",buffer);
  225.         fflush(stdout);
  226.         fgets(in_line, SLEN, stdin);
  227.         if (strlen(in_line) > 1)
  228.           fprintf(fd,"%s%s",buffer,in_line);
  229.  
  230.         strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerUrgent, "*****URGENT******  - "));
  231.         printf("%s",buffer);
  232.         fflush(stdout);
  233.         fgets(in_line, SLEN, stdin);
  234.         if (strlen(in_line) > 1)
  235.           fprintf(fd,"%s%s",buffer,in_line);
  236.       }
  237.  
  238.       printf(catgets(elm_msg_cat, AnswerSet, AnswerEnterMessage,
  239.         "\n\nEnter message for %s ending with a blank line.\n\n"), 
  240.          user_name);
  241.  
  242.       fprintf(fd,"\n\n");
  243.  
  244.       do {
  245.        printf("> ");
  246.        if (! (eof = (fgets(buffer, SLEN, stdin) == NULL))) 
  247.          fprintf(fd, "%s", buffer);
  248.       } while (! eof && strlen(buffer) > 1);
  249.     
  250.       fclose(fd);
  251.  
  252.       sprintf(buffer, catgets(elm_msg_cat, AnswerSet, AnswerElmCommand,
  253.          "( ( %s -s \"While You Were Out\" %s ; %s %s) & ) < %s > /dev/null"),
  254.          ELM, strip_parens(address), remove_cmd, tempfile, tempfile);
  255.  
  256.       system(buffer);
  257.     }
  258. }
  259.  
  260. int
  261. translate(fullname, name)
  262. char *fullname, *name;
  263. {
  264.     /** translate fullname into name..
  265.            'first last'  translated to first_initial - underline - last
  266.            'initial last' translated to initial - underline - last
  267.         Return 0 if error.
  268.     **/
  269.     register int i, lastname = 0, len;
  270.  
  271.     for (i=0, len = strlen(fullname); i < len; i++) {
  272.  
  273.       if (isupper(fullname[i]))
  274.          fullname[i] = tolower(fullname[i]);
  275.  
  276.       if (fullname[i] == ' ') 
  277.         if (lastname) {
  278.           printf(catgets(elm_msg_cat, AnswerSet, AnswerCannotHaveMoreNames,
  279.           "** Can't have more than 'FirstName LastName' as address!\n"));
  280.           return(0);
  281.         }
  282.         else
  283.           lastname = i+1;
  284.     
  285.     }
  286.  
  287.     if (lastname) 
  288.       sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
  289.     else
  290.       strcpy(name, fullname);
  291.  
  292.     return(1);
  293. }
  294.  
  295.         
  296. open_alias_file()
  297. {
  298.     /** open the user alias file **/
  299.  
  300.     char fname[SLEN];
  301.  
  302.     sprintf(fname,  "%s/.elm/aliases", getenv("HOME")); 
  303.  
  304.     if ((hash = dbz_open(fname, O_RDONLY, 0)) == NULL) 
  305.       exit(printf("** Fatal Error: Could not open %s!\n", fname));
  306.  
  307.     if ((user_data = open(fname, O_RDONLY)) == -1) 
  308.       return;
  309. }
  310.  
  311. char *get_alias_address(name, mailing, depth)
  312. char *name;
  313. int   mailing, depth;
  314. {
  315.     /** return the line from either datafile that corresponds 
  316.         to the specified name.  If 'mailing' specified, then
  317.         fully expand group names.  Returns NULL if not found.
  318.         Depth is the nesting depth, and varies according to the
  319.         nesting level of the routine.  **/
  320.  
  321.     static char buffer[VERY_LONG_STRING];
  322.     static char sprbuffer[VERY_LONG_STRING];
  323.     datum  key, value;
  324.     int    loc;
  325.     struct alias_rec entry;
  326.  
  327.     name = shift_lower(name);
  328.     key.dptr = name;
  329.     key.dsize = strlen(name);
  330.     value = dbz_fetch(hash, key);
  331.     if (value.dptr == NULL)
  332.         return( (char *) NULL); /* not found */
  333.  
  334.     bcopy(value.dptr, (char *) &loc, sizeof(loc));
  335.     loc -= sizeof(entry);
  336.     lseek(user_data, loc, 0L);
  337.     read(user_data, (char *) &entry, sizeof(entry));
  338.     read(user_data, buffer, entry.length > VERY_LONG_STRING ? VERY_LONG_STRING : entry.length);
  339.     if ((entry.type & GROUP) != 0 && mailing) {
  340.         if (expand_group(sprbuffer, buffer + (int) entry.address,
  341.                  depth) < 0)
  342.         return NULL;
  343.     } else {
  344.         sprintf(sprbuffer, "%s (%s)", buffer + (int) entry.address,
  345.             buffer + (int) entry.name);
  346.     }
  347.     return sprbuffer;
  348. }
  349.  
  350. int expand_group(target, members, depth)
  351. char *target;
  352. char *members;
  353. int   depth;
  354. {
  355.     /** given a group of names separated by commas, this routine
  356.         will return a string that is the full addresses of each
  357.         member separated by spaces.  Depth is the current recursion
  358.         depth of the expansion (for the 'get_token' routine) **/
  359.  
  360.     char   buf[VERY_LONG_STRING], *word, *address, *bufptr;
  361.  
  362.     strcpy(buf, members);     /* parameter safety! */
  363.     target[0] = '\0';    /* nothing in yet!   */
  364.     bufptr = (char *) buf;    /* grab the address  */
  365.     depth++;        /* one more deeply into stack */
  366.  
  367.     while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
  368.       if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
  369.         fprintf(stderr, catgets(elm_msg_cat, AnswerSet, AnswerNotFoundForGroup,
  370.         "Alias %s not found for group expansion!\n"), word);
  371.         return -1;
  372.       }
  373.       else if (strcmp(target,address) != 0) {
  374.         sprintf(target + strlen(target), " %s", address);
  375.       }
  376.  
  377.       bufptr = NULL;
  378.     }
  379.     return 0;
  380. }
  381.  
  382. print_long(buffer, init_len)
  383. char *buffer;
  384. int   init_len;
  385. {
  386.     /** print buffer out, 80 characters (or less) per line, for
  387.         as many lines as needed.  If 'init_len' is specified, 
  388.         it is the length that the first line can be.
  389.     **/
  390.  
  391.     register int i, loc=0, space, length, len; 
  392.  
  393.     /* In general, go to 80 characters beyond current character
  394.        being processed, and then work backwards until space found! */
  395.  
  396.     length = init_len;
  397.  
  398.     do {
  399.       if (strlen(buffer) > loc + length) {
  400.         space = loc + length;
  401.         while (buffer[space] != ' ' && space > loc + 50) space--;
  402.         for (i=loc;i <= space;i++)
  403.           putchar(buffer[i]);
  404.         putchar('\n');
  405.         loc = space;
  406.       }
  407.       else {
  408.         for (i=loc, len = strlen(buffer);i < len;i++)
  409.           putchar(buffer[i]);
  410.         putchar('\n');
  411.         loc = len;
  412.       }
  413.       length = 80;
  414.     } while (loc < strlen(buffer));
  415. }
  416.  
  417. /****
  418.      The following is a newly chopped version of the 'strtok' routine
  419.   that can work in a recursive way (up to 20 levels of recursion) by
  420.   changing the character buffer to an array of character buffers....
  421. ****/
  422.  
  423. #define MAX_RECURSION        20        /* up to 20 deep recursion */
  424.  
  425. #undef  NULL
  426. #define NULL            (char *) 0    /* for this routine only   */
  427.  
  428. extern char *strpbrk();
  429.  
  430. char *get_token(string, sepset, depth)
  431. char *string, *sepset;
  432. int  depth;
  433. {
  434.  
  435.     /** string is the string pointer to break up, sepstr are the
  436.         list of characters that can break the line up and depth
  437.         is the current nesting/recursion depth of the call **/
  438.  
  439.     register char    *p, *q, *r;
  440.     static char    *savept[MAX_RECURSION];
  441.  
  442.     /** is there space on the recursion stack? **/
  443.  
  444.     if (depth >= MAX_RECURSION) {
  445.      fprintf(stderr, catgets(elm_msg_cat, AnswerSet, AnswerRecursionTooDeep,
  446.         "Error: Get_token calls nested greater than %d deep!\n"),
  447.             MAX_RECURSION);
  448.      exit(1);
  449.     }
  450.  
  451.     /* set up the pointer for the first or subsequent call */
  452.     p = (string == NULL)? savept[depth]: string;
  453.  
  454.     if(p == 0)        /* return if no tokens remaining */
  455.         return(NULL);
  456.  
  457.     q = p + strspn(p, sepset);    /* skip leading separators */
  458.  
  459.     if (*q == '\0')        /* return if no tokens remaining */
  460.         return(NULL);
  461.  
  462.     if ((r = strpbrk(q, sepset)) == NULL)    /* move past token */
  463.         savept[depth] = 0;    /* indicate this is last token */
  464.     else {
  465.         *r = '\0';
  466.         savept[depth] = ++r;
  467.     }
  468.     return(q);
  469. }
  470.